package project1;


public abstract class ICommand {
	protected byte seqNumber;
	protected int type;
	
	public ICommand(byte seqNumber, int type) {
		this.seqNumber = seqNumber;
		this.type = type;
	}
	
	public static ICommand createInstance(byte seqNumber, int type) {
		if (type == 0x01) {
			// Register
			return new RegisterCommand(seqNumber, type);
		} else if (type == 0x03) {
			// Fetch
			return new FetchCommand(seqNumber, type);
		} else if (type == 0x05) {
			// Unregister
			return new FetchCommand(seqNumber, type);
		} else if (type == 0x06) {
			// Probe
			return new ProbeCommand(seqNumber, type);
		} else {
			throw new IllegalArgumentException("Given type is not recognised as command type.");
		}
	}
	
	//TODO: Find a way to reduce the ip parameter
	public static ICommand createInstanceFromCommand(String commandStr, byte seqNumber, byte[] ip) {
		String[] command = commandStr.split(" ");
		if (command.length == 0) {
			Util.printUsage();
			throw new IllegalArgumentException("Illegal Command String.");
		}
		int type = -1;
		if (command[0].equals("r")) {
			if (command.length != 4) {
				Util.printUsage();
				throw new IllegalArgumentException("Illegal Command String.");
			}
			// Register
			type = 0x01;
			RegisterCommand comm = new RegisterCommand(seqNumber, type);
			long data = 0;
			try {
				data = Long.parseLong(command[3]);
			} catch (Exception e) {
				Util.printUsage();
				throw new IllegalArgumentException("Illegal data format.");
			}
			comm.setServiceData(data);
			comm.setServiceIp(ip);
			comm.setServiceName(command[1]);
			comm.setServicePort(Integer.parseInt(command[2]));
			return comm;
			
		} else if (command[0].equals("u")) {
			if (command.length != 2) {
				Util.printUsage();
				throw new IllegalArgumentException("Illegal Command String.");
			}
			// Unregister
			type = 0x05;
			FetchCommand comm = new FetchCommand(seqNumber, type);
			if (WaitResponseThread.rrtl.containsKey(command[1])) {
				WaitResponseThread.rrtl.get(command[1]).close();
			}
			comm.setServiceName(command[1]);
			return comm;
			
		} else if (command[0].equals("f")) {
			if (command.length > 2) {
				Util.printUsage();
				throw new IllegalArgumentException("Illegal Command String.");
			}
			// Fetch
			type = 0x03;
			FetchCommand comm = new FetchCommand(seqNumber, type);
			if (command.length == 2)
				comm.setServiceName(command[1]);
			return comm;
			
		} else if (command[0].equals("p")) {
			if (command.length != 1) {
				Util.printUsage();
				throw new IllegalArgumentException("Illegal Command String.");
			}
			// Probe
			type = 0x06;
			ProbeCommand comm = new ProbeCommand(seqNumber, type);
			return comm; 
			
		} else {
			Util.printUsage();
			throw new IllegalArgumentException("Illegal Command String.");
		}
	}
	
	public abstract byte[] generateMessage();
	
	public int getType() {
		return type;
	}
	
	public byte getSeqNum() {
		return seqNumber;
	}
	
	public void setSeqNum(byte seqNumber) {
		this.seqNumber = seqNumber;
	}
}
